﻿/*!
 * @filemixtureofgaussian.h
 * Staufferらによる手法
 * 参考文献: Adaptive background mixture models for real-time tracking
 * @author 橋本敦史
 * @date Last Change:2010/Apr/06.
 */
#ifndef __BGS_DYNAMIC_MIXTURE_OF_GAUSSIAN_H__
#define __BGS_DYNAMIC_MIXTURE_OF_GAUSSIAN_H__

#include "MmplVector.h"
#include <vector>
#include <iostream>
#include "ImageBackgroundSubtractAlgorithm.h"
#include "CSVReader.h"

namespace mmpl{
	namespace image{
		struct SphericalGaussian{
			//! 各軸の平均値
			MmplVector means;
			//! 球状のガウス分布を仮定しているので、分散は一つ
			double sigma;
		};

		struct MixtureOfSphericalGaussian{
			std::vector<SphericalGaussian> distributions;
			MmplVector weights;
		};

		void calcProb(MmplVector& sample,MixtureOfSphericalGaussian& model,MmplVector* probs);

		void writeAsCsv(const SphericalGaussian& dist, std::ostream& out);
		void writeAsCsv(const MixtureOfSphericalGaussian& mog, std::ostream& out);
		void readFromCsv(SphericalGaussian* dist, CSVReader& csvr);
		void readFromCsv(MixtureOfSphericalGaussian* mog, CSVReader& csvr);

/*!
 * @class 混合正規分布により背景の各画素をモデル化し、動的に背景モデルを更新しながら背景差分を行うクラス
 */
class BackgroundSubtractorDynamicMixtureOfGaussian: public BackgroundSubtractAlgorithm{

	public:
		BackgroundSubtractorDynamicMixtureOfGaussian(double threshold=0.025,double alpha = 0.01,double sigma = 60.0);
		virtual ~BackgroundSubtractorDynamicMixtureOfGaussian();

		void setBGModel(const std::vector<MixtureOfSphericalGaussian>& bgmodel);
		void getBGMeanImage(int rank, Image* oimg)const;
		void getBGDistNumImage(Image* oimg, double amplifier=32.0)const;
		void apply(const Image& img,BGSubtractedImage* oimg);

		virtual void update(const Image& img,const short int* regionLabels, const std::vector<bool>& maskRegionFlags);
		void apply(const Image& img,BGSubtractedImage* oimg, bool update,std::vector<MmplVector>* probsVec=NULL);	

		
		void load(const std::string& filename);
		void save(const std::string& filename)const;


		/********* Accessor ********/
		void setSigma(double sigma);
		const std::vector<MixtureOfSphericalGaussian>* getBGModel()const;
		void setBGImage(const Image& bgimage, double sigma = 0);
		size_t getWidth()const;
		size_t getHeight()const;
		void setThreshold(double threshold);
		double getThreshold()const;
		void setAlpha(double alpha);
		double getAlpha()const;
		void doUpdateInApply(bool update);
	protected:
	    virtual void updateByBackGroundColor(MixtureOfSphericalGaussian* mog, const Color& col,const MmplVector& probs);	
		virtual void updateByForeGroundColor(MixtureOfSphericalGaussian* mog, const Color& col,const MmplVector& probs);

		std::vector<MixtureOfSphericalGaussian> bgmodel;
		int width;
		int height;

		//! apply関数の中でupdateも行うか否か
		bool updateInApply;

		//! 背景差分のapply関数の中で計算された各画素が背景である確率
		std::vector<MmplVector> probsVec;

		//! setBGImageなどで背景モデルを新しく作成する際の分散の初期値
		double sigma;

		//! もっとも良くマッチした分布の確率がthreshold未満なら前景とみなす
		double threshold;
		//! 学習率(大きければ早く現状にフィッティングする)
		double alpha;
	private:
		
};


	} // namespace image

} // namespace skl
#endif // __BackgroundSubtractorMIXTUREOFGAUSSIAN_H__

